    /*  
    championBuilder - Champions Online character planner.
    Copyright (C) 2009 Moritz Hartmeier
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You can find the GNU General Public License in the data folder.
    */


package ch.zarzu.champions.builder;

import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SpringLayout;
import javax.swing.filechooser.FileFilter;
import javax.swing.Box;

import ch.zarzu.champions.builder.gui.MainInterface;
import ch.zarzu.champions.builder.logic.BuildUpdater;
import ch.zarzu.champions.builder.logic.Listener;
import ch.zarzu.champions.builder.updater.AutoUpdater;
import ch.zarzu.util.AppPath;
import ch.zarzu.util.ExtensionFileFilter;
import ch.zarzu.util.OSXAdapter;

public class Main extends JPanel implements WindowListener {
    private static final long serialVersionUID = 1L;
    
    private JFrame frame;
    public JMenuItem save_menu;
    private Container root_pane;
    
    private SystemLink sys_link;
    private PrefLink pref_link;
    private MainInterface user_interface;
    private Listener listener;
    private BuildUpdater updater;
    // private AutoUpdater auto_updater; -- this isn't working, lets remove it for now -- AL
    
    private String app_path;
    
    private HashMap<String, JRadioButtonMenuItem> language_menus;
    private HashMap<String, JMenuItem> menu_items;
    
    private static Main instance = null;
        
    private Main() {
        if (App.IS_OSX) {
            try {
                OSXAdapter.setQuitHandler(this, this.getClass().getDeclaredMethod("handleQuit", (Class[]) null));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        pref_link = PrefLink.getInstance();
        sys_link = SystemLink.getInstance();
        sys_link.parseXml();
        listener = Listener.getInstance();
        updater = BuildUpdater.getInstance();
        
        user_interface = MainInterface.getInstance();
        user_interface.init();
    }

    public void addComponentsToPane (Container pane) {
        SpringLayout layout = new SpringLayout();
        pane.setLayout(layout);
        
        root_pane = pane;
        
        LinkedList<Component> list = user_interface.getComponents();
        Component s;
        
        s = list.get(list.size() - 1);
        pane.add(s);
        layout.putConstraint(SpringLayout.WEST, s, 0, SpringLayout.WEST, pane);
        layout.putConstraint(SpringLayout.NORTH, s, 0, SpringLayout.NORTH, pane);
        layout.putConstraint(SpringLayout.EAST, pane, 0, SpringLayout.EAST, s);
        layout.putConstraint(SpringLayout.SOUTH, pane, 0, SpringLayout.SOUTH, s);
        
        for(int i = 0; i < list.size() - 1; i++) {
            s = list.get(i);
            pane.add(s);
            layout.putConstraint(SpringLayout.EAST, s, 0, SpringLayout.EAST, pane);
            layout.putConstraint(SpringLayout.SOUTH, s, 0, SpringLayout.SOUTH, pane);
            layout.putConstraint(SpringLayout.WEST, s, 0, SpringLayout.WEST, pane);
            layout.putConstraint(SpringLayout.NORTH, s, 0, SpringLayout.NORTH, pane);
        }
    }
    
    //Create the GUI and show it.
    void createAndShowGUI(String build) {
        app_path = AppPath.get();
        
        System.out.println("app_path => " + app_path);
        
        String title = "championBuilder v" + App.VERSION;
        
        if (App.IS_OSX) {
            title = "ChampionBuilder";
        }
        
        frame = new JFrame(title);
        frame.addWindowListener(this);
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addComponentsToPane(frame.getContentPane());

        //add the menu
        
        JMenuBar menu_bar;
        JMenu menu, submenu;
        JMenuItem menu_item;
        menu_items = new HashMap<String, JMenuItem>();
        
        menu_bar = new JMenuBar();

        menu = new JMenu(sys_link.translate("menu_file"));
        menu_bar.add(menu);
        menu_items.put("menu_file", menu);

        menu_item = new JMenuItem(sys_link.translate("menu_new"));
        menu_item.setActionCommand("new");
        menu_item.addActionListener(listener);
        menu_item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
        menu.add(menu_item);
        menu_items.put("menu_new",menu_item);

        menu_item = new JMenuItem(sys_link.translate("menu_open"));
        menu_item.setActionCommand("open");
        menu_item.addActionListener(listener);
        menu_item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
        menu.add(menu_item);
        menu_items.put("menu_open",menu_item);

        menu.addSeparator();
        
        menu_item = new JMenuItem(sys_link.translate("menu_saveas"));
        menu_item.setActionCommand("saveas");
        menu_item.addActionListener(listener);
        menu.add(menu_item);
        menu_items.put("menu_saveas",menu_item);
        
        menu_item = new JMenuItem(sys_link.translate("menu_save"));
        menu_item.setActionCommand("save");
        menu_item.addActionListener(listener);
        menu_item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
        menu.add(menu_item);
        save_menu = menu_item;
        menu_items.put("menu_save",menu_item);
        
        menu.addSeparator();
        
        menu_item = new JMenuItem(sys_link.translate("menu_print"));
        menu_item.setActionCommand("print");
        menu_item.addActionListener(listener);
        menu_item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK));
        menu.add(menu_item);
        menu_items.put("menu_print",menu_item);
        
        if (!App.IS_OSX) {
            menu.addSeparator();
            
            menu_item = new JMenuItem(sys_link.translate("menu_exit"));
            menu_item.setActionCommand("exit");
            menu_item.addActionListener(listener);
            menu_item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
            menu.add(menu_item);
            menu_items.put("menu_exit",menu_item);
        }
        
        menu = new JMenu(sys_link.translate("menu_export"));
        menu.setBorder(null);
        menu_bar.add(menu);
        menu_items.put("menu_export",menu);

        menu_item = new JMenuItem(sys_link.translate("menu_normalforumexport"));
           menu_item.setActionCommand("normalforumexport");
           menu_item.addActionListener(listener);
           menu_item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, ActionEvent.CTRL_MASK));
        menu.add(menu_item);
        menu_items.put("menu_normalforumexport",menu_item);

        menu_item = new JMenuItem(sys_link.translate("menu_plaintextexport"));
        menu_item.setActionCommand("plaintextexport");
        menu_item.addActionListener(listener);
        menu.add(menu_item);
        menu_items.put("menu_plaintextexport",menu_item);
        
        menu.addSeparator();
        
        // Not needed only held Language Options
        /*
        menu = new JMenu(sys_link.translate("menu_options"));
        menu.setBorder(null);
        menu_bar.add(menu);
        menu_items.put("menu_options",menu_item);

        submenu = new JMenu(sys_link.translate("menu_language"));
        
        language_menus = new HashMap<String, JRadioButtonMenuItem>();
        JRadioButtonMenuItem radioItem;
        for(String lang_choice : sys_link.getString("languages").keySet()) {
            radioItem = new JRadioButtonMenuItem(sys_link.getString("languages").get(lang_choice));
            radioItem.setActionCommand("language:" + lang_choice);
            radioItem.addActionListener(listener);
            language_menus.put(lang_choice, radioItem);
            if(pref_link.getPreference("language").equals(lang_choice)) {
                radioItem.setSelected(true);
            }
            submenu.add(radioItem);
        }
        menu.add(submenu);
        menu_items.put("menu_language",submenu);*/
        menu_bar.add(Box.createHorizontalGlue());
        
        menu = new JMenu(sys_link.translate("menu_help"));
        menu.setBorder(null);
        menu_bar.add(menu);
        menu_items.put("menu_help",menu);

        menu_item = new JMenuItem(sys_link.translate("menu_cb_help"));
        menu_item.setActionCommand("help");
        menu_item.addActionListener(listener);
        menu.add(menu_item);
        menu_items.put("menu_cb_help",menu_item);
        
        menu_item = new JMenuItem(sys_link.translate("menu_about"));
        menu_item.setActionCommand("about");
        menu_item.addActionListener(listener);
        menu.add(menu_item);
        menu_items.put("menu_about",menu_item);
        
        
        menu_bar.setBorder(null);
        frame.setJMenuBar(menu_bar);


        
        System.out.println(pref_link.getLastSaved());
        //directly opening a file (not working)
        if(!build.equals("")) {
            updater.loadBuild(new File(build));
            pref_link.updateLastSaved(build);
        //open last saved file automatically
        } else if(!pref_link.getLastSaved().equals(""))
            updater.loadBuild(new File(pref_link.getLastSaved()));
        
        //start the auto updater
        /* Disabled by Abel_Lindburg 03/20/2011
        auto_updater = new AutoUpdater();
        auto_updater.start();
        */
        
        user_interface.setChanged(false);
        
        updateBackground();
        
        //display the window
        frame.pack();
        frame.setVisible(true);
    }
    
    //window events
    public void windowClosing(WindowEvent e) {
        exit();
    }
    public void windowClosed(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowActivated(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowGainedFocus(WindowEvent e) {}
    public void windowLostFocus(WindowEvent e) {}
    public void windowStateChanged(WindowEvent e) {}

    /**
     * updates to the currently chosen language
     */
    public void updateLanguage() {
        for(String s : menu_items.keySet()) {
            menu_items.get(s).setText(sys_link.translate(s));
        }
        
        boolean active;
        for(String s : language_menus.keySet()) {
            if(pref_link.getPreference("language").equals(s))
                active = true;
            else
                active = false;
            
            language_menus.get(s).setSelected(active);
        }
    }
    
    public void repaintFrame() {
        frame.getContentPane().repaint();
    }
    
    public void updateBackground() {
        root_pane.setBackground(App.background);
    }
    
    //save to current file or show a popup if it isn't associated with a file yet
    public boolean saveBuild() {
        String last_saved = pref_link.getPreference("last_saved_0");
        
        if(!last_saved.equals("")) {
            updater.saveBuild(new File(last_saved));
            return true;
        }
        else
            return saveBuildAs();
    }
    
    //save builds with a popup selector
    public boolean saveBuildAs() {
        JFileChooser chooser = new JFileChooser();
        
        chooser.setCurrentDirectory(new java.io.File(pref_link.getSaveFolder()));
        chooser.setDialogTitle(sys_link.translate("chooser_save"));
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setAcceptAllFileFilterUsed(false);
        FileFilter filter = new ExtensionFileFilter("chb-files", new String[] { "chb", "chb" });
        chooser.setFileFilter(filter);
        
        //send the selected file to the updater for saving, or do nothing
        if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            String path = chooser.getSelectedFile().getAbsolutePath();
            if(!path.endsWith("chb")) {
                path += ".chb";
            }
            File file = new File(path);
            updater.saveBuild(file);
            return true;
        } else
            return false;
    }
    
    public void openBuild() {
        JFileChooser chooser = new JFileChooser();
        
        System.out.println(pref_link.getSaveFolder());
        chooser.setCurrentDirectory(new java.io.File(pref_link.getSaveFolder()));
        chooser.setDialogTitle(sys_link.translate("chooser_open"));
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setAcceptAllFileFilterUsed(false);
        FileFilter filter = new ExtensionFileFilter("chb-files", new String[] { "chb", "chb" });
        chooser.setFileFilter(filter);
        
        //send the selected file to the updater for saving, or do nothing
        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { 
          updater.loadBuild(chooser.getSelectedFile());
        }
    }
    
    //exit the program and update it
    public void startUpdate() {
        boolean success = true;
        if(user_interface.isChanged()) {
            success = saveYesNoCancel();
        }
        if(success) {
            String ext;
            if(App.DIST.equals("exe"))
                ext = ".exe";
            else
                ext = ".jar";
            try {
                Runtime.getRuntime().exec(app_path + "updater" + ext);
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.exit(0);
        }
    }
    
    //exit the program and download the newest version
    public void startDownload() {
        boolean success = true;
        if(user_interface.isChanged()) {
            success = saveYesNoCancel();
        }
        /*if(success) {
            boolean browser_success = showInBrowser(auto_updater.getDownloadLink());
            if(browser_success)
                System.exit(0);
            else {
                JOptionPane.showMessageDialog(frame, sys_link.translate("browser_error"));
            }
        
        }*/
        JOptionPane.showMessageDialog(frame, sys_link.translate("browser_error"));
    }
    
    //dialog for saving, returns true if it either saved or no saving is necessary, false on cancel
    private boolean saveYesNoCancel() {
        String msg = "";
        String last_saved = pref_link.getPreference("last_saved_0");
        if(!last_saved.equals(""))
            msg = sys_link.translate("pop_save_1").replace("(1)", new File(last_saved).getName());
        else
            msg = sys_link.translate("pop_save_2");
        
        Object[] options = {sys_link.translate("yes"),
                            sys_link.translate("no"),
                            sys_link.translate("cancel")};
        int n = JOptionPane.showOptionDialog(frame,
            msg,
            sys_link.translate("pop_save_title"),
            JOptionPane.YES_NO_CANCEL_OPTION,
            JOptionPane.QUESTION_MESSAGE,
            null,
            options,
            options[2]);
        if(n == 0) {
            if(saveBuild())
                return true;
            else
                return false;
        } else if(n == 1) {
            return true;
        } else {
            return false;
        }
    }
    
    public boolean handleQuit() {
        if(user_interface.isChanged()) {
            return saveYesNoCancel();
        }
        
        return true;
    }
    
    //exit the program
    public void exit() {
        if(this.handleQuit()) {
            System.exit(0);
        }
    }

    /**
     * Opens a web site in the browser. This is easier in jre6 with the Desktop 
     * class, but jre5 needs to be supported.
     * 
     * @param   url     the URL of the web site to be opened.
     * @return          true if it succeeded.
     */
    public boolean showInBrowser(String url) {
        Runtime rt = Runtime.getRuntime();
        try {
            if (App.IS_WINDOWS) {
                String[] cmd = new String[4];
                cmd[0] = "cmd.exe";
                cmd[1] = "/C";
                cmd[2] = "start";
                cmd[3] = url;
                rt.exec(cmd);
            
            } else if (App.IS_OSX) {
                rt.exec("open " + url);
            
            } else {
                //prioritized guess of users' preference
                String[] browsers = {"epiphany", "chrome", "firefox", "mozilla", 
                        "konqueror", "netscape", "opera", "links", "lynx"};
                
                StringBuffer cmd = new StringBuffer();
                for (int i=0; i<browsers.length; i++)
                cmd.append( (i==0  ? "" : " || " ) + browsers[i] +" \"" + url + "\" ");
                
                rt.exec(new String[] { "sh", "-c", cmd.toString() });
            }
        } catch (IOException e) {
            e.printStackTrace();
            
            return false;
        }
        return true;
    }
    
    public static Main getInstance() {
        if(instance == null)
            instance = new Main();
        return instance;
    }
}
